home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-9.10-netbook-remix-PL.iso / casper / filesystem.squashfs / usr / share / pyshared / nevow / json.py < prev    next >
Text File  |  2007-10-30  |  8KB  |  324 lines

  1. # -*- test-case-name: nevow.test.test_json -*-
  2. # Copyright (c) 2004-2007 Divmod.
  3. # See LICENSE for details.
  4.  
  5. """
  6. JavaScript Object Notation.
  7.  
  8. This is not (nor does it intend to be) a faithful JSON implementation, but it
  9. is kind of close.
  10. """
  11.  
  12. import re, types
  13.  
  14. from nevow.inevow import IAthenaTransportable
  15. from nevow import rend, page, flat, tags
  16.  
  17. class ParseError(ValueError):
  18.     pass
  19.  
  20. whitespace = re.compile(
  21.             r'('
  22.             r'[\r\n\t\ ]+'
  23.             r'|/\*.*?\*/'
  24.             r'|//[^\n]*[\n]'
  25.             r')'
  26.             , re.VERBOSE + re.DOTALL)
  27. openBrace = re.compile(r'{')
  28. closeBrace = re.compile(r'}')
  29. openSquare = re.compile(r'\[')
  30. closeSquare = re.compile(r'\]')
  31.  
  32. class StringTokenizer(object):
  33.     """
  34.     because r'(?<!\\)"([^"]+|\\")*(?<!\\)"'
  35.     """
  36.  
  37.     def match(self, s):
  38.         if not s.startswith('"'):
  39.             return None
  40.  
  41.         bits = []
  42.  
  43.         SLASH = "\\"
  44.  
  45.         IT = iter(s)
  46.         bits = [IT.next()]
  47.         for char in IT:
  48.             bits.append(char)
  49.             if char == SLASH:
  50.                 try:
  51.                     bits.append(IT.next())
  52.                 except StopIteration:
  53.                     return None
  54.             if char == '"':
  55.                 self.matched = ''.join(bits)
  56.                 return self
  57.  
  58.         return None
  59.  
  60.     def group(self, num):
  61.         return self.matched
  62.  
  63. string = StringTokenizer()
  64. identifier = re.compile(r'[A-Za-z_][A-Za-z_0-9]*')
  65. colon = re.compile(r':')
  66. comma = re.compile(r',')
  67. true = re.compile(r'true')
  68. false = re.compile(r'false')
  69. null = re.compile(r'null')
  70. floatNumber = re.compile(r'-?([1-9][0-9]*|0)(\.[0-9]+)([eE][-+]?[0-9]+)?')
  71. longNumber = re.compile(r'-?([1-9][0-9]*|0)([eE][-+]?[0-9]+)?')
  72.  
  73. class StringToken(str):
  74.     pass
  75.  
  76. class IdentifierToken(str):
  77.     pass
  78.  
  79. class WhitespaceToken(object):
  80.     pass
  81.  
  82. def jsonlong(s):
  83.     if 'e' in s:
  84.         m, e = map(long, s.split('e', 1))
  85.     else:
  86.         m, e = long(s), 0
  87.     return m * 10 ** e
  88.  
  89. # list of tuples, the first element is a compiled regular expression the second
  90. # element returns a token and the original string.
  91. actions = [
  92.     (whitespace, lambda s: (WhitespaceToken, s)),
  93.     (openBrace, lambda s: ('{',s)),
  94.     (closeBrace, lambda s: ('}',s)),
  95.     (openSquare, lambda s: ('[',s)),
  96.     (closeSquare, lambda s: (']',s)),
  97.     (string, lambda s: (StringToken(s), s)),
  98.     (colon, lambda s: (':', s)),
  99.     (comma, lambda s: (',', s)),
  100.     (true, lambda s: (True, s)),
  101.     (false, lambda s: (False, s)),
  102.     (null, lambda s: (None, s)),
  103.     (identifier, lambda s: (IdentifierToken(s), s)),
  104.     (floatNumber, lambda s: (float(s), s)),
  105.     (longNumber, lambda s: (jsonlong(s), s)),
  106. ]
  107. def tokenise(s):
  108.     tokens = []
  109.     while s:
  110.         for regexp, action in actions:
  111.             m = regexp.match(s)
  112.             if m:
  113.                 tok, tokstr = action(m.group(0))
  114.                 break
  115.         else:
  116.             raise ValueError, "Invalid Input, %r" % (s[:10],)
  117.  
  118.         if tok is not WhitespaceToken:
  119.             tokens.append(tok)
  120.         s = s[len(tokstr):]
  121.  
  122.     return tokens
  123.  
  124. def accept(want, tokens):
  125.     t = tokens.pop(0)
  126.     if want != t:
  127.         raise ParseError, "Unexpected %r, %s expected" % (t , want)
  128.  
  129. def parseValue(tokens):
  130.     if tokens[0] == '{':
  131.         return parseObject(tokens)
  132.  
  133.     if tokens[0] == '[':
  134.         return parseList(tokens)
  135.  
  136.     if tokens[0] in (True, False, None):
  137.         return tokens.pop(0), tokens
  138.  
  139.     if type(tokens[0]) == StringToken:
  140.         return parseString(tokens)
  141.  
  142.     if type(tokens[0]) in (int, float, long):
  143.         return tokens.pop(0), tokens
  144.  
  145.     raise ParseError, "Unexpected %r" % tokens[0]
  146.  
  147.  
  148. _stringExpr = re.compile(
  149.     ur'(?:\\x(?P<unicode>[a-fA-F0-9]{2})) # Match hex-escaped unicode' u'\n'
  150.     ur'|' u'\n'
  151.     ur'(?:\\u(?P<unicode2>[a-fA-F0-9]{4})) # Match hex-escaped high unicode' u'\n'
  152.     ur'|' u'\n'
  153.     ur'(?P<control>\\[fbntr\\"]) # Match escaped control characters' u'\n',
  154.     re.VERBOSE)
  155.  
  156. _controlMap = {
  157.     u'\\f': u'\f',
  158.     u'\\b': u'\b',
  159.     u'\\n': u'\n',
  160.     u'\\t': u'\t',
  161.     u'\\r': u'\r',
  162.     u'\\"': u'"',
  163.     u'\\\\': u'\\',
  164.     }
  165.  
  166. def _stringSub(m):
  167.     u = m.group('unicode')
  168.     if u is None:
  169.         u = m.group('unicode2')
  170.     if u is not None:
  171.         return unichr(int(u, 16))
  172.     c = m.group('control')
  173.     return _controlMap[c]
  174.  
  175.  
  176. def parseString(tokens):
  177.     if type(tokens[0]) is not StringToken:
  178.         raise ParseError, "Unexpected %r" % tokens[0]
  179.     s = _stringExpr.sub(_stringSub, tokens.pop(0)[1:-1].decode('utf-8'))
  180.     return s, tokens
  181.  
  182.  
  183. def parseIdentifier(tokens):
  184.     if type(tokens[0]) is not IdentifierToken:
  185.         raise ParseError("Unexpected %r" % (tokens[0],))
  186.     return tokens.pop(0), tokens
  187.  
  188.  
  189. def parseList(tokens):
  190.     l = []
  191.     tokens.pop(0)
  192.     first = True
  193.     while tokens[0] != ']':
  194.         if not first:
  195.             accept(',', tokens)
  196.         first = False
  197.  
  198.         value, tokens = parseValue(tokens)
  199.         l.append(value)
  200.  
  201.     accept(']', tokens)
  202.     return l, tokens
  203.  
  204.  
  205. def parseObject(tokens):
  206.     o = {}
  207.     tokens.pop(0)
  208.     first = True
  209.     while tokens[0] != '}':
  210.         if not first:
  211.             accept(',', tokens)
  212.         first = False
  213.  
  214.         name, tokens = parseString(tokens)
  215.         accept(':', tokens)
  216.         value, tokens = parseValue(tokens)
  217.         o[name] = value
  218.  
  219.     accept('}', tokens)
  220.     return o, tokens
  221.  
  222.  
  223. def parse(s):
  224.     """
  225.     Return the object represented by the JSON-encoded string C{s}.
  226.     """
  227.     tokens = tokenise(s)
  228.     value, tokens = parseValue(tokens)
  229.     if tokens:
  230.         raise ParseError, "Unexpected %r" % tokens[0]
  231.     return value
  232.  
  233. class CycleError(Exception):
  234.     pass
  235.  
  236. _translation = dict([(o, u'\\x%02x' % (o,)) for o in range(0x20)])
  237.  
  238. _translation.update({
  239.     ord(u'\\'): u'\\\\',
  240.     ord(u'"'): ur'\"',
  241.     ord(u'\f'): ur'\f',
  242.     ord(u'\b'): ur'\b',
  243.     ord(u'\n'): ur'\n',
  244.     ord(u'\t'): ur'\t',
  245.     ord(u'\r'): ur'\r',
  246.     })
  247.  
  248. def stringEncode(s):
  249.     return s.translate(_translation).encode('utf-8')
  250.  
  251.  
  252. def _serialize(obj, w, seen):
  253.     from nevow import athena
  254.  
  255.     if isinstance(obj, types.BooleanType):
  256.         if obj:
  257.             w('true')
  258.         else:
  259.             w('false')
  260.     elif isinstance(obj, (int, long, float)):
  261.         w(str(obj))
  262.     elif isinstance(obj, unicode):
  263.         w('"')
  264.         w(stringEncode(obj))
  265.         w('"')
  266.     elif isinstance(obj, types.NoneType):
  267.         w('null')
  268.     elif id(obj) in seen:
  269.         raise CycleError(type(obj))
  270.     elif isinstance(obj, (tuple, list)):
  271.         w('[')
  272.         for n, e in enumerate(obj):
  273.             _serialize(e, w, seen)
  274.             if n != len(obj) - 1:
  275.                 w(',')
  276.         w(']')
  277.     elif isinstance(obj, dict):
  278.         w('{')
  279.         for n, (k, v) in enumerate(obj.iteritems()):
  280.             _serialize(k, w, seen)
  281.             w(':')
  282.             _serialize(v, w, seen)
  283.             if n != len(obj) - 1:
  284.                 w(',')
  285.         w('}')
  286.     elif isinstance(obj, (athena.LiveFragment, athena.LiveElement)):
  287.         _serialize(obj._structured(), w, seen)
  288.     elif isinstance(obj, (rend.Fragment, page.Element)):
  289.         wrapper = tags.div(xmlns="http://www.w3.org/1999/xhtml")
  290.         w('"')
  291.         w(stringEncode(flat.flatten(wrapper[obj]).decode('utf-8')))
  292.         w('"')
  293.     else:
  294.         transportable = IAthenaTransportable(obj, None)
  295.         if transportable is not None:
  296.             w('(new ' + transportable.jsClass.encode('ascii') + '(')
  297.             arguments = transportable.getInitialArguments()
  298.             for n, e in enumerate(arguments):
  299.                 _serialize(e, w, seen)
  300.                 if n != len(arguments) - 1:
  301.                     w(',')
  302.             w('))')
  303.         else:
  304.             raise TypeError("Unsupported type %r: %r" % (type(obj), obj))
  305.  
  306.  
  307.  
  308. _undefined = object()
  309. def serialize(obj=_undefined, **kw):
  310.     """
  311.     JSON-encode an object.
  312.  
  313.     @param obj: None, True, False, an int, long, float, unicode string,
  314.     list, tuple, or dictionary the JSON-encoded form of which will be
  315.     returned.
  316.     """
  317.     if obj is _undefined:
  318.         obj = kw
  319.     L = []
  320.     _serialize(obj, L.append, {})
  321.     return ''.join(L)
  322.  
  323. __all__ = ['parse', 'serialize']
  324.